/** @file        base64.cpp
  * @brief       Base64的编解码
  * @details   
  * @author      皓瑞
  * @date        2020-01-10
  * @version     V1.0
  * @copyright   
  **********************************************************************************
  * @attention
  **********************************************************************************
*/

/* Includes ------------------------------------------------------------------*/
#include "baiduyun/base64.h"

using namespace std;

std::string Base64::Encode(const char* data,int dataByte)
{
    /* Base64编码表 */
    const char EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    string strEncode;             //编码完的数据     
    strEncode.reserve( static_cast<size_t>(dataByte*1.5 + 10) );
    unsigned char temp[4] = {0};
    int lineLength        = 0;
    int mod               = dataByte % 3;

    /*！ 对编码长度为3的倍数的部分进行Base64编码 */
    for(int i=0; i<(int)(dataByte/3); i++)
    {
        temp[1] = *data++;
        temp[2] = *data++;
        temp[3] = *data++;
        strEncode+= EncodeTable[temp[1] >> 2];
        strEncode+= EncodeTable[((temp[1] << 4) | (temp[2] >> 4)) & 0x3F];
        strEncode+= EncodeTable[((temp[2] << 2) | (temp[3] >> 6)) & 0x3F];
        strEncode+= EncodeTable[temp[3] & 0x3F];
        lineLength+=4;
        /* 每76个字符加一个换行符 */
        if(lineLength==76) {
            //strEncode+="\n";
            lineLength=0;
        }
    }

    /* 对剩余数据进行编码 */
    if(mod==1){
        temp[1] = *data++;
        strEncode += EncodeTable[(temp[1] & 0xFC) >> 2];
        strEncode += EncodeTable[((temp[1] & 0x03) << 4)];
        strEncode += "==";
    }
    else if(mod==2){
        temp[1] = *data++;
        temp[2] = *data++;
        strEncode+= EncodeTable[(temp[1] & 0xFC) >> 2];
        strEncode+= EncodeTable[((temp[1] & 0x03) << 4) | ((temp[2] & 0xF0) >> 4)];
        strEncode+= EncodeTable[((temp[2] & 0x0F) << 2)];
        strEncode+= "=";
    }
    
    return strEncode;
}

string Base64::Decode(const char* data,int dataByte)
{
    /* Base64解码表(一行十个) */
    const char DecodeTable[] ={
           0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
           0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
           0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
           0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
           0,  0,  0, 62,  0,  0,  0, 63, 52,  53,
          54, 55, 56, 57, 58, 59, 60, 61,  0,  0, 
           0,  0,  0,  0,  0,  0,  1,  2,  3,  4,
           5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
          15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
          25,  0, 63,  0,  0,  0,  0, 26, 27, 28,
          29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
          39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
          49, 50, 51
    };
    string strDecode;         //解码完的数据   
    int nValue  = 0;          //辅助变量
    int i       = 0;
    int outByte = 0;

    while (i < dataByte){
        if (*data != '\r' && *data != '\n'){
            nValue = DecodeTable[*data++] << 18;         //  (18 = 24-6*1)
            nValue += DecodeTable[*data++] << 12;        //  (12 = 24-6*2)
            strDecode+=(nValue & 0x00FF0000) >> 16;      //  解码第一个字符
            outByte++;
            if (*data != '='){
                nValue += DecodeTable[*data++] << 6;     //  (6 = 24-6*3)
                strDecode+=(nValue & 0x0000FF00) >> 8;   //  解码第二个字符
                outByte++;
                if (*data != '='){
                    nValue += DecodeTable[*data++];     //  (0 = 24-6*4)
                    strDecode+=nValue & 0x000000FF;     //  解码第三个字符
                    outByte++;
                }
            }
            i += 4;
        }
        /* 回车换行,跳过 */
        else{
            data++;
            i++;
        }
     }
    return strDecode;
}